﻿using Logger;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.Gaming.Input;
using Windows.Media;
using Windows.Media.Core;
using Windows.Media.Playback;

namespace Xiaowei.Players.XiaoweiPlayerLib
{
    /// <summary>
    /// 播放声音的具体实现
    /// </summary>
    public class XiaoweiPlayerAudio
    {
        MediaPlayer MediaPlayer { get; set; } = null;
        SystemMediaTransportControls smtc = null;
        public XiaoweiPlayerAudio()
        {
            CreateMediaPlayer();
        }
        MediaCommandEnablingRule GetMediaCommandEnablingRule(bool isEnable)
        {
            if (isEnable) return MediaCommandEnablingRule.Always;
            else return MediaCommandEnablingRule.Never;
        }
        public void InitSMTC()
        {
            Debug.WriteLine("XiaoweiPlayerAudio, InitSMTC");
            Task.Run(()=> {
                if (MediaPlayer == null) return;
                smtc = MediaPlayer.SystemMediaTransportControls;
                Debug.WriteLine("lock wait:InitSMTC()");
                lock (smtc)
                {
                    Debug.WriteLine("lock enter:InitSMTC()");
                    Debug.WriteLine("XiaoweiPlayerAudio, InitSMTC, smtc Enter");
                    smtc.IsEnabled = true;
                    smtc.IsPlayEnabled = XiaoweiPlayerList != null;
                    smtc.IsPauseEnabled = XiaoweiPlayerList != null;
                    smtc.IsNextEnabled = XiaoweiPlayerList != null && XiaoweiPlayerList.CanGoNext;
                    smtc.IsPreviousEnabled = XiaoweiPlayerList != null && XiaoweiPlayerList.CanGoPre;
                    smtc.ButtonPressed += Smtc_ButtonPressed;
                    Debug.WriteLine("XiaoweiPlayerAudio, InitSMTC, smtc End");
                }
            });
        }

        private void Smtc_ButtonPressed(SystemMediaTransportControls sender, SystemMediaTransportControlsButtonPressedEventArgs args)
        {
            switch (args.Button)
            {
                case SystemMediaTransportControlsButton.Play:
                    Play();
                    break;
                case SystemMediaTransportControlsButton.Pause:
                    Pause();
                    break;
                case SystemMediaTransportControlsButton.Stop:
                    Pause();
                    break;
                case SystemMediaTransportControlsButton.Next:
                    Next();
                    break;
                case SystemMediaTransportControlsButton.Previous:
                    Prev();
                    break;
                default:
                    break;
            }
        }

        public void DisposeSMTC()
        {
            Debug.WriteLine("XiaoweiPlayerAudio, DisposeSMTC");
            Task.Run(()=> {
                if (smtc == null) return;
                Debug.WriteLine("lock wait: DisposeSMTC()");
                lock (smtc)
                {
                    Debug.WriteLine("lock enter: DisposeSMTC()");
                    Debug.WriteLine("XiaoweiPlayerAudio, DisposeSMTC, smtc enter");
                    smtc.IsEnabled = false;
                    smtc.ButtonPressed -= Smtc_ButtonPressed;
                    Debug.WriteLine("XiaoweiPlayerAudio, DisposeSMTC, smtc end");
                }
                smtc = null;
            });
        }
        private IXiaoweiPlayerList xiaoweiPlayerList;
        public IXiaoweiPlayerList XiaoweiPlayerList
        {
            get
            {
                return xiaoweiPlayerList;
            }
            set
            {
                if (xiaoweiPlayerList != value)
                {
                    DisposeList();
                    xiaoweiPlayerList = value;
                    InitList();
                }
            }
        }

        private void DisposeList()
        {
            Debug.WriteLine("XiaoweiPlayerAudio, DisposeList");
            if (XiaoweiPlayerList != null)
            {
                XiaoweiPlayerList.CurrentItemChanged -= XiaoweiPlayerListBase_CurrentItemChanged;
                XiaoweiPlayerList.CanGoNextChanged -= XiaoweiPlayerListBase_CanGoNextChanged;
                XiaoweiPlayerList.CanGoPreChanged -= XiaoweiPlayerListBase_CanGoPreChanged;
                if (xiaoweiPlayerList is IXiaoweiPlayerList2 list)
                {
                    list.RefreshURLEnd -= List_RefreshURLEnd;
                }
                //Task.Run(()=> {
                //    if (mpcm != null)
                //    {
                //        mpcm.PlayBehavior.EnablingRule = MediaCommandEnablingRule.Never;
                //        mpcm.PauseBehavior.EnablingRule = MediaCommandEnablingRule.Never;
                //    }
                //});
                xiaoweiPlayerList.Suspend();
                Pause();
            }
        }

        private void InitList()
        {
            Debug.WriteLine("XiaoweiPlayerAudio, InitList");
            if (MediaPlayer == null) return;
            if (XiaoweiPlayerList != null)
            {
                XiaoweiPlayerList.CurrentItemChanged += XiaoweiPlayerListBase_CurrentItemChanged;
                XiaoweiPlayerList.CanGoNextChanged += XiaoweiPlayerListBase_CanGoNextChanged;
                XiaoweiPlayerList.CanGoPreChanged += XiaoweiPlayerListBase_CanGoPreChanged;
                if(xiaoweiPlayerList is IXiaoweiPlayerList2 list)
                {
                    list.RefreshURLEnd += List_RefreshURLEnd;
                }
                xiaoweiPlayerList.Resumed();

                Task.Run(() => {
                    try
                    {
                        currentItem = XiaoweiPlayerList.CurrentItem;
                        MediaPlayer.Source = MediaSource.CreateFromUri(new Uri(XiaoweiPlayerList.CurrentItem?.MediaUri));
                        Play();
                    }
                    catch
                    {
                        RefresahCurrentURL();
                    }

                    if (smtc != null)
                    {
                        Debug.WriteLine("lock wait: InitList()");
                        lock (smtc)
                        {
                            Debug.WriteLine("lock enter: InitList()");
                            Debug.WriteLine("XiaoweiPlayerAudio, InitList, mpcm Enter");
                            smtc.IsPlayEnabled=true;
                            smtc.IsPauseEnabled=true;
                            smtc.IsEnabled = true;
                            smtc.IsPreviousEnabled=xiaoweiPlayerList.CanGoPre;
                            smtc.IsPauseEnabled=xiaoweiPlayerList.CanGoNext;
                            Debug.WriteLine("XiaoweiPlayerAudio, InitList, mpcm End");
                        }
                    }
                });

            }
            else
            {
                MediaPlayer.Source = null;
                Task.Run(()=> {
                    if (smtc != null)
                    {
                        Debug.WriteLine("lock wait: InitList2()");
                        lock (smtc)
                        {
                            Debug.WriteLine("lock enter: InitList2()");
                            Debug.WriteLine("XiaoweiPlayerAudio, InitList, smtc2 Enter");
                            smtc.IsEnabled = false;
                            Debug.WriteLine("XiaoweiPlayerAudio, InitList, smtc2 End");
                        }
                    }
                });

            }

            Debug.WriteLine("XiaoweiPlayerAudio, InitList, End");
        }

        private void List_RefreshURLEnd(XiaoweiPlayerItemBase obj)
        {
            isRefreshing = false;
            if(currentItem==obj)
            {
                XiaoweiPlayerListBase_CurrentItemChanged(null,obj);
            }
        }

        private void XiaoweiPlayerListBase_CanGoPreChanged(object sender, EventArgs e)
        {
            Debug.WriteLine("XiaoweiPlayerAudio, CanGoPreChanged");
            Task.Run(() =>
            {
                if (smtc != null)
                {
                    Debug.WriteLine("lock wait: XiaoweiPlayerListBase_CanGoPreChanged");
                    lock (smtc)
                    {
                        Debug.WriteLine("lock enter: XiaoweiPlayerListBase_CanGoPreChanged");
                        Debug.WriteLine("XiaoweiPlayerAudio, CanGoPreChanged, smtc Enter");
                        smtc.IsPreviousEnabled=xiaoweiPlayerList.CanGoPre;
                        Debug.WriteLine("XiaoweiPlayerAudio, CanGoPreChanged, smtc End");
                    }
                }
            });
        }

        private void XiaoweiPlayerListBase_CanGoNextChanged(object sender, EventArgs e)
        {
            Debug.WriteLine("XiaoweiPlayerAudio, CanGoNextChanged");
            Task.Run(() =>
            {
                if (smtc != null)
                {
                    Debug.WriteLine("lock wait:XiaoweiPlayerListBase_CanGoNextChanged");
                    lock (smtc)
                    {
                        Debug.WriteLine("lock enter:XiaoweiPlayerListBase_CanGoNextChanged");
                        Debug.WriteLine("XiaoweiPlayerAudio, CanGoNextChanged, smtc Enter");
                        smtc.IsNextEnabled = xiaoweiPlayerList.CanGoNext;
                        Debug.WriteLine("XiaoweiPlayerAudio, CanGoNextChanged, smtc End");
                    }
                }
            });

        }

        private bool isRefreshing = false;

        private async void RefresahCurrentURL()
        {
            isRefreshing = true;
            Stop();
            
            PlayerStateChanged?.Invoke(this,EventArgs.Empty);
            if(XiaoweiPlayerList is IXiaoweiPlayerList2 list&& currentItem != null)
            {
                list.GetURL(currentItem.PlayId) ;
                await Task.Delay(10000).ConfigureAwait(false);
                if(isRefreshing)
                {
                    isRefreshing = false;
                    Next();
                }
            }
            else
            {
                Next();
            }
        }

        XiaoweiPlayerItemBase currentItem;

        private void XiaoweiPlayerListBase_CurrentItemChanged(object sender, XiaoweiPlayerItemBase e)
        {
            currentItem = e;
            Task.Run(() =>
            {
                if (MediaPlayer == null) return;
                if (e != null)
                {
                    
                    try
                    {
                        MediaPlayer.Source = MediaSource.CreateFromUri(new Uri(e.MediaUri));
                        Play();
                    }
                    catch
                    {
                        RefresahCurrentURL();


                    }

                }
            });
        }

        private void MediaPlayer_MediaEnded(MediaPlayer sender, object args)
        {
            XiaoweiPlayerList?.CurrentPlayEnd();
        }
        public PlayerState PlayerState
        {
            get
            {
                PlayerState playerState = PlayerState.Stop;
                if (MediaPlayer == null) return playerState;
                if (isRefreshing) return PlayerState.Buffering;
                switch (MediaPlayer.PlaybackSession.PlaybackState)
                {
                    case MediaPlaybackState.None:
                        playerState = PlayerState.Stop;
                        break;
                    case MediaPlaybackState.Opening:
                        playerState = PlayerState.Buffering;
                        break;
                    case MediaPlaybackState.Buffering:
                        playerState = PlayerState.Buffering;
                        break;
                    case MediaPlaybackState.Playing:
                        playerState = PlayerState.Play;
                        break;
                    case MediaPlaybackState.Paused:
                        playerState = PlayerState.Pause;
                        break;
                    default:
                        break;
                }
                return playerState;
            }
        }
        public event EventHandler PlayerStateChanged;
        private void PlaybackSession_PlaybackStateChanged(MediaPlaybackSession sender, object args)
        {
            PlayerStateChanged?.Invoke(this, EventArgs.Empty);
        }
        public TimeSpan Position
        {
            get
            {
                if (playerState.IsDisposed)
                {
                    return playerState.Position;
                }
                return MediaPlayer.PlaybackSession.Position;
            }
        }
        public event EventHandler PositionChanged;
        private void PlaybackSession_PositionChanged(MediaPlaybackSession sender, object args)
        {
            PositionChanged?.Invoke(this, EventArgs.Empty);
        }

        public TimeSpan Duration
        {
            get
            {
                if (playerState.IsDisposed)
                {
                    return playerState.Duration;
                }
                return MediaPlayer.PlaybackSession.NaturalDuration;
            }
        }
        public event EventHandler DurationChanged;
        private void PlaybackSession_NaturalDurationChanged(MediaPlaybackSession sender, object args)
        {
            DurationChanged?.Invoke(this, EventArgs.Empty);
        }
        public void Play()
        {
            Task.Run(() =>
            {
                MediaPlayer?.Play();
            });
        }
        public void Pause()
        {
            Task.Run(() =>
            {
                MediaPlayer?.Pause();
            });
        }
        public void Stop()
        {
            Task.Run(() =>
            {
                MediaPlayer?.Pause();
            });
        }
        public void FastForward(int seconds)
        {
            Task.Run(() =>
            {
                if (MediaPlayer == null) return;
                TimeSpan position = MediaPlayer.PlaybackSession.Position + TimeSpan.FromSeconds(seconds);
                MediaPlayer.PlaybackSession.Position = position;
            });
        }
        public void FastRewind(int seconds)
        {
            Task.Run(() =>
            {
                if (MediaPlayer == null) return;
                TimeSpan position = MediaPlayer.PlaybackSession.Position - TimeSpan.FromSeconds(seconds);
                if (position < TimeSpan.FromSeconds(0))
                {
                    position = TimeSpan.FromSeconds(0);
                }
                MediaPlayer.PlaybackSession.Position = position;
            });
        }
        public void Next()
        {
            XiaoweiPlayerList?.GoNext();
        }

        public void Prev()
        {
            XiaoweiPlayerList?.GoPre();
        }

        public void SeekTo(int seconds)
        {
            Task.Run(()=> {
                if (MediaPlayer == null) return;
                MediaPlayer.PlaybackSession.Position = TimeSpan.FromSeconds(seconds);
            });

        }

        private readonly object playerLocker = new object();
        private struct MediaPlayerState
        {
            public TimeSpan Position { get; set; }
            public TimeSpan Duration { get; set; }
            public IMediaPlaybackSource MediaSource { get; set; }
            public bool IsDisposed { get; set; }
            public MediaPlaybackState PlayState { get; set; }
        }

        MediaPlayerState playerState = new MediaPlayerState
        {
            Position = TimeSpan.MinValue,
            Duration = TimeSpan.MinValue,
            MediaSource = null,
            IsDisposed = true,
            PlayState = MediaPlaybackState.None
        };

        public void DestroyMediaPlayer()
        {
            Task.Run(()=> {
                lock (playerLocker)
                {
                    if (!playerState.IsDisposed && MediaPlayer != null)
                    {
                        Debug.WriteLine($"XiaoweiPlayerAudio.DestroyMediaPlayer, Enter, playstate:{MediaPlayer.PlaybackSession.PlaybackState}");
                        playerState.MediaSource = MediaPlayer.Source;
                        playerState.Position = MediaPlayer.PlaybackSession.Position;
                        playerState.PlayState = MediaPlayer.PlaybackSession.PlaybackState;
                        playerState.IsDisposed = true;
                        DisposeSMTC();

                        MediaPlayer.PlaybackSession.NaturalDurationChanged -= PlaybackSession_NaturalDurationChanged;
                        MediaPlayer.PlaybackSession.PositionChanged -= PlaybackSession_PositionChanged;
                        MediaPlayer.MediaEnded -= MediaPlayer_MediaEnded;
                        MediaPlayer.PlaybackSession.PlaybackStateChanged -= PlaybackSession_PlaybackStateChanged;
                        MediaPlayer.Dispose();
                        MediaPlayer = null;
                        Debug.WriteLine("XiaoweiPlayerAudio.DestroyMediaPlayer, End");
                    }
                }
            });

        }

        public void CreateMediaPlayer()
        {
            Task.Run(()=> {
                lock (playerLocker)
                {
                    if (playerState.IsDisposed)
                    {
                        Debug.WriteLine($"XiaoweiPlayerAudio.CreateMediaPlayer, Enter, playstate:{playerState.PlayState}");
                        MediaPlayer = new MediaPlayer();
                        MediaPlayer.CommandManager.IsEnabled = false;
                        MediaPlayer.PlaybackSession.NaturalDurationChanged += PlaybackSession_NaturalDurationChanged;
                        MediaPlayer.PlaybackSession.PositionChanged += PlaybackSession_PositionChanged;
                        MediaPlayer.MediaEnded += MediaPlayer_MediaEnded;
                        MediaPlayer.PlaybackSession.PlaybackStateChanged += PlaybackSession_PlaybackStateChanged;
                        MediaPlayer.MediaFailed += MediaPlayer_MediaFailed;
                        MediaPlayer.Source = playerState.MediaSource;
                        MediaPlayer.PlaybackSession.Position = playerState.Position;
                        
                        if (playerState.PlayState == MediaPlaybackState.Playing)
                        {
                            Debug.WriteLine("XiaoweiPlayerAudio.CreateMediaPlayer, Pause playing audios");
                            MediaPlayer.Pause();
                        }

                        playerState.IsDisposed = false;
                        InitSMTC();
                        Debug.WriteLine("XiaoweiPlayerAudio.CreateMediaPlayer, End");
                    }
                }
            });

        }

        private void MediaPlayer_MediaFailed(MediaPlayer sender, MediaPlayerFailedEventArgs args)
        {
            RefresahCurrentURL();
        }
    }
}
